﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using System.Globalization;
using Microsoft.Win32;
using System.ServiceProcess;
using Microsoft.SharePoint.Administration;
using System.IO;
using System.Collections;
using Microsoft.SharePoint.Utilities;
using System.Reflection;

namespace SPALM
{
    /// <summary>
    /// Checks conditions e.g. to be used before a deployment
    /// </summary>
    public class CoreTask : Task
    {
        public CoreTask()
            : base()
        {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
        }

        static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
            //we only get once into this method, because we only reference the Microsoft.SharePoint.dll

            //File.AppendAllText(logFile, "SharePointBridge.exe: Resolve " + args.Name + Environment.NewLine);
            string assemblyFullname = args.Name;

            if(assemblyFullname.StartsWith("Microsoft.SharePoint", StringComparison.InvariantCultureIgnoreCase))
            {
                //File.AppendAllText(logFile, "SharePointBridge.exe: Microsoft.SharePoint.* reqeusted" + Environment.NewLine);
            
                if(assemblyFullname.Contains("12.0.0.0"))
                {
                    assemblyFullname = assemblyFullname.Replace("12.0.0.0", "14.0.0.0");
                    //File.AppendAllText(logFile, "SharePointBridge.exe: Returning assembly " + assemblyFullname + Environment.NewLine);
                    Assembly assembly = Assembly.Load(assemblyFullname);
                    //File.AppendAllText(logFile, "SharePointBridge.exe: Loaded from GAC = " + assembly.GlobalAssemblyCache.ToString() + Environment.NewLine);

                    AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);

                    return assembly;
                }
                else if(assemblyFullname.Contains("14.0.0.0"))
                {
                    assemblyFullname = assemblyFullname.Replace("14.0.0.0", "12.0.0.0");
                    //File.AppendAllText(logFile, "SharePointBridge.exe: Returning assembly " + assemblyFullname + Environment.NewLine);
                    Assembly assembly = Assembly.Load(assemblyFullname);
                    //File.AppendAllText(logFile, "SharePointBridge.exe: Loaded from GAC = " + assembly.GlobalAssemblyCache.ToString() + Environment.NewLine);

                    AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
                    
                    return assembly;
                }
            }

            //search in same dir
            string firstTest = Path.Combine(GetAssemblyDirectory(), args.Name);
            if (File.Exists(firstTest))
            {
                //File.AppendAllText(logFile, "SharePointBridge.exe: Returned assembly " + firstTest + Environment.NewLine);
                return Assembly.LoadFile(firstTest, Assembly.GetExecutingAssembly().Evidence);
            }

			string assemblySearchDir = GetSharePointHive() + @"\ISAPI";

			string[] asmName = args.Name.Split(',');
			string asmPath = Path.Combine(assemblySearchDir, asmName[0] + ".dll");

            return Assembly.LoadFile(asmPath, Assembly.GetExecutingAssembly().Evidence);
		}		

        internal static string GetAssemblyDirectory()
        {
            string codeBase = Assembly.GetExecutingAssembly().CodeBase;
            UriBuilder uri = new UriBuilder(codeBase);
            string path = Uri.UnescapeDataString(uri.Path);
            return Path.GetDirectoryName(path);        
        }

        internal static string GetSharePointHive()
		{
			return GetCommonProgramsFolder() + "\\Microsoft Shared\\web server extensions\\" + GetInstalledSharePointVersion();
		}

        internal static string GetInstalledSharePointVersion()
		{
			//is there a folder /14/Template, check only for 12 or 14 is not enough because 
			//folder 12 is sometimes also on 14er installations available (with bin folder)
			string check14Folder = GetCommonProgramsFolder() + "\\Microsoft Shared\\web server extensions\\" + 14 + "\\Template";
			if (Directory.Exists(check14Folder))
			{
				return "14";
			}
			return "12";
		}

        public static string GetCommonProgramsFolder()
		{
			string commonProgramFolder = System.Environment.GetEnvironmentVariable("CommonProgramW6432");
			if (string.IsNullOrEmpty(commonProgramFolder))
			{
				commonProgramFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);
			}
			return commonProgramFolder;
		}

        private const string DisplayMSBuildExtensionVersion = "DisplayMSBuildExtensionVersion";
        private const string CheckMOSSInstalled = "CheckMOSSInstalled";
        private const string CheckWSSInstalled = "CheckWSSInstalled";
        private const string CheckMinimalVersionInstalled = "CheckMinimalVersionInstalled";
        private const string CheckUserIsAdministrator = "CheckUserIsAdministrator";
        private const string CheckAdminServiceRunning = "CheckAdminServiceRunning";
        private const string CheckTimerServiceRunning = "CheckTimerServiceRunning";
        private const string CheckSolutionDeployed = "CheckSolutionDeployed";
        private const string CheckWebApplicationExists = "CheckWebApplicationExists";
        private const string CheckSiteExists = "CheckSiteExists";
        private const string CheckWebExists = "CheckWebExists";
        private const string CheckPrerequisiteSolutions = "CheckPrerequisiteSolutions";
        private const string CheckIfSolutionExists = "CheckIfSolutionExists";
        private const string GetWebApplicationSolutions = "GetWebApplicationSolutions";
        private const string CheckSolutionDeployment = "CheckSolutionDeployment";
        private const string CheckSolutionUndeployment = "CheckSolutionUndeployment";
        private const string CheckSolutionRemove = "CheckSolutionRemove";
        private const string WaitForSolutionDeploymentFinished = "WaitForSolutionDeploymentFinished";
        private const string GetSTSADMPath = "GetSTSADMPath";
        private const string GetPowerShellConsolePath = "GetPowerShellConsolePath";
        private const string Sleep = "Sleep";


        public virtual string TaskAction { get; set; }

        public virtual string MinimalVersion { get; set; }

        public virtual string Url { get; set; }

        public virtual string Solutions { get; set; }
        
        public virtual int MilliSeconds { get; set; }

        [Output]
        public ITaskItem[] WebApplicationSolutions
        {
            get
            {
                return webapplicationSolutions;
            }
        }

        [Output]
        public string STSADMPath
        {
            get
            {
                string path = Path.Combine(SPUtility.GetGenericSetupPath("BIN"), "stsadm.exe");
                Log.LogMessageFromText("Retrieving path to stsadm: " + path, MessageImportance.Low);
                return path;
            }
        }

        [Output]
        public string PowerShellConsolePath
        {
            get
            {
                string path = Path.Combine(SPUtility.GetGenericSetupPath("Config"), "POWERSHELL\\Registration\\psconsole.psc1");
                Log.LogMessageFromText("Retrieving path to powershell console: " + path, MessageImportance.Low);
                return path;
            }
        }

        [Output]
        public ITaskItem[] GloballySolutions
        {
            get
            {
                return globallySolutions;
            }
        }

        public ITaskItem ToTaskItem(string value)
        {
            TaskItem item = new TaskItem(value);
            item.SetMetadata("Value", value);
            item.SetMetadata("Type", value.GetType().ToString());
            return item;
        }
        private ITaskItem[] webapplicationSolutions;
        private ITaskItem[] globallySolutions;

        public override bool Execute()
        {
            switch (this.TaskAction)
            {
                case DisplayMSBuildExtensionVersion:
                    return this.RunDisplayMSBuildExtensionVersion();
                case CheckMOSSInstalled:
                    return this.RunCheckMOSSInstalled();
                case CheckWSSInstalled:
                    return this.RunCheckWSSInstalled();
                case CheckMinimalVersionInstalled:
                    return this.RunCheckMinimalVersionInstalled();
                case CheckUserIsAdministrator:
                    return this.RunCheckUserIsAdministrator();
                case CheckAdminServiceRunning:
                    return this.RunCheckAdminServiceRunning();
                case CheckTimerServiceRunning:
                    return this.RunCheckTimerServiceRunning();
                case CheckWebApplicationExists:
                    return this.RunCheckWebApplicationExists();
                case CheckSiteExists:
                    return this.RunCheckSiteExists();
                case CheckWebExists:
                    return this.RunCheckWebExists();
                case CheckPrerequisiteSolutions:
                    return this.RunCheckPrerequisiteSolutions();
                case CheckIfSolutionExists:
                    return this.RunCheckIfSolutionExists();
                case GetWebApplicationSolutions:
                    return this.RunGetWebApplicationSolutions();
                case CheckSolutionDeployment:
                    return this.RunCheckSolutionDeployment();
                case CheckSolutionUndeployment:
                    return this.RunCheckSolutionUndeployment();
                case CheckSolutionRemove:
                    return this.RunCheckSolutionRemove();
                case WaitForSolutionDeploymentFinished:
                    return this.RunWaitForSolutionDeploymentFinished();
                case GetSTSADMPath:
                    return this.RunGetSTSADMPath();
                case GetPowerShellConsolePath:
                    return this.RunGetPowerShellConsolePath();
                case Sleep:
                    return this.RunSleep();
                default:
                    Log.LogError(string.Format(CultureInfo.CurrentCulture, "Invalid TaskAction passed: {0}", this.TaskAction));
                    return false;
            }
        }



        private bool RunDisplayMSBuildExtensionVersion()
        {
            Log.LogMessageFromText("Version of SPALM.dll: " + System.Diagnostics.FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion, MessageImportance.Normal);
            return true;
        }

        private bool RunSleep()
        {
            Log.LogMessageFromText("Sleeping " + MilliSeconds + " milliseconds.", MessageImportance.Normal);

            System.Threading.Thread.Sleep(this.MilliSeconds);
            return true;
        }

        private bool RunGetSTSADMPath()
        {
            return true;
        }

        private bool RunGetPowerShellConsolePath()
        {
            return true;
        }

        private bool RunWaitForSolutionDeploymentFinished()
        {
            
            //waits that no solution deployment is running
            bool deployFinished = false;
            int maxWaiting = 20;
            int currentWaiting = 0;

            try
            {
                while (!deployFinished)
                {
                    deployFinished = true;
                    foreach (SPSolution solution in SPFarm.Local.Solutions)
                    {
                        if ((solution.JobExists)) // || (solution.Status == SPObjectStatus.Provisioning) || (solution.Status == SPObjectStatus.Unprovisioning) || (solution.Status == SPObjectStatus.Upgrading))
                        {
                            Log.LogMessageFromText("Waiting for solution " + solution.Name + "(" + solution.JobStatus.ToString() + ")", MessageImportance.Normal);
                            deployFinished = false;
                        }
                    }

                    if (currentWaiting > maxWaiting)
                    {
                        throw new Exception("Solution deployment failed. Timeout reached.");
                    }

                    if (!deployFinished)
                    {
                        System.Threading.Thread.Sleep(5000);
                        currentWaiting++;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }
            

            //ExecAdmSvcJobs();

            Log.LogMessageFromText("Solutions successfully deployed.", MessageImportance.Normal);
            return true;
        }

        private bool RunCheckSolutionUndeployment()
        {
            return InternalCheckSolutionDeploymentStatus(false);
        }

        private bool RunCheckSolutionDeployment()
        {
            return InternalCheckSolutionDeploymentStatus(true);
        }

        private bool RunCheckSolutionRemove()
        {
            bool throwException = false;
            string message = "";
            char[] sep = new char[';'];
            string[] solutionNames = Solutions.Split(';');
            try
            {
                SPSolutionCollection solutions = SPFarm.Local.Solutions;

                foreach (string solutionName in solutionNames)
                {
                    string checkName = solutionName;
                    if (checkName.Contains("\\"))
                    {
                        checkName = checkName.Substring(checkName.IndexOf("\\") + 1);
                    }

                    //Log.LogMessageFromText("Checking solution '" + checkName + "'...", MessageImportance.Normal);

                    foreach (SPSolution solution in solutions)
                    {
                        if (solution.Name.Equals(checkName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            //ups, solution already in solution store
                            throwException = true;
                            message += "Solution '" + solution.Name + "' still found in solution store; ";
                        }
                    }
                }
            }
            catch { }

            if (throwException)
            {
                Log.LogErrorFromException(new Exception(message));
                return false;
            }
            return true;
        }

        private bool InternalCheckSolutionDeploymentStatus(bool checkForDeployment)
        {
            bool throwException = false;
            string message = "";

            if (Solutions == null)
            {
                return true;
            }

            if (checkForDeployment)
            {
                //Solutions can come as Customizations\ApplicationName22.Resources1.wsp
                Log.LogMessageFromText("Checking solutions '" + Solutions + "' for successful deployment.", MessageImportance.Normal);
            }
            else
            {
                //Solutions can come as Customizations\ApplicationName22.Resources1.wsp
                Log.LogMessageFromText("Checking solutions '" + Solutions + "' for successful undeployment.", MessageImportance.Normal);
            }

            char[] sep = new char[';'];
            string[] solutionNames = Solutions.Split(';');
            try
            {
                SPSolutionCollection solutions = SPFarm.Local.Solutions;

                foreach (string solutionName in solutionNames)
                {
                    string checkName = solutionName;
                    if (checkName.Contains("\\"))
                    {
                        checkName = checkName.Substring(checkName.IndexOf("\\") + 1);
                    }

                    //Log.LogMessageFromText("Checking solution '" + checkName + "'...", MessageImportance.Normal);

                    foreach (SPSolution solution in solutions)
                    {
                        if (solution.Name.Equals(checkName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            if (checkForDeployment)
                            {
                                if (solution.Deployed)
                                {
                                    //everything: OK
                                    Log.LogMessageFromText("Solution '" + checkName + "' deployed successfully", MessageImportance.Normal);
                                }
                                else
                                {
                                    throwException = true;
                                    message += "Solution '" + checkName + "' not deployed successfully; ";
                                    Log.LogMessageFromText("Error: Solution '" + checkName + "' not deployed successfully (" + solution.LastOperationDetails + ")", MessageImportance.Normal);
                                }
                            }
                            else
                            {
                                if (!solution.Deployed)
                                {
                                    //everything: OK
                                    Log.LogMessageFromText("Solution '" + checkName + "' undeployed successfully", MessageImportance.Normal);
                                }
                                else
                                {
                                    throwException = true;
                                    message += "Solution '" + checkName + "' not successfully undeployed; ";
                                    Log.LogMessageFromText("Error: Solution '" + checkName + "' not undeployed successfully (" + solution.LastOperationDetails + ")", MessageImportance.Normal);
                                }
                            }
                        }
                    }
                }

                Log.LogMessageFromText(" ", MessageImportance.Normal);
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }
            if (throwException)
            {
                Log.LogErrorFromException(new Exception(message));
                return false;
            }
            return true;
        }

        private bool DeploymentHasWarnings(SPSolution solution)
        {
            if (solution.LastOperationResult == SPSolutionOperationResult.DeploymentWarningsOccurred)
            {
                return true;
            }
            if (solution.LastOperationResult == SPSolutionOperationResult.RetractionWarningsOccurred)
            {
                return true;
            }
            return false;
        }

        private bool DeploymentFinished(SPSolution solution)
        {
            if (solution.LastOperationResult == SPSolutionOperationResult.DeploymentSucceeded)
            {
                return true;
            }
            if (solution.LastOperationResult == SPSolutionOperationResult.RetractionSucceeded)
            {
                return true;
            }
            return false;
        }

        internal bool DeploymentIsInProgress(SPSolution solution)
        {
            if (solution.LastOperationResult == SPSolutionOperationResult.NoOperationPerformed)
            {
                return true;
            }
            return false;
        }

        private bool DeploymentFailed(SPSolution solution)
        {
            if (solution.LastOperationResult == SPSolutionOperationResult.DeploymentFailedFeatureInstall)
            {
                return true;
            }
            if (solution.LastOperationResult == SPSolutionOperationResult.DeploymentFailedFileCopy)
            {
                return true;
            }
            if (solution.LastOperationResult == SPSolutionOperationResult.DeploymentSolutionValidationFailed)
            {
                return true;
            }
            if (solution.LastOperationResult == SPSolutionOperationResult.DeploymentFailedCabExtraction)
            {
                return true;
            }

            if (solution.LastOperationResult == SPSolutionOperationResult.RetractionFailedCouldNotRemoveFeature)
            {
                return true;
            }
            if (solution.LastOperationResult == SPSolutionOperationResult.RetractionFailedCouldNotRemoveFile)
            {
                return true;
            }

            return false;
        }

        private bool RunGetWebApplicationSolutions()
        {
            ArrayList webappSolutionArray = new ArrayList();
            ArrayList globalSolutionArray = new ArrayList();

            if (Solutions == null)
            {
                return true;
            }

            //Solutions can come as Customizations\ApplicationName22.Resources1.wsp
            Log.LogMessageFromText("Getting information from SharePoint which solutions '" + Solutions + "' contains web application resource.", MessageImportance.Normal);

            char[] sep = new char[';'];
            string[] solutionNames = Solutions.Split(';');

            try
            {
                SPSolutionCollection solutions = SPFarm.Local.Solutions;

                foreach (string solutionName in solutionNames)
                {
                    string checkName = solutionName;
                    if (checkName.Contains("\\"))
                    {
                        checkName = checkName.Substring(checkName.IndexOf("\\") + 1);
                    }

                    //Log.LogMessageFromText("Checking solution '" + checkName + "' ", MessageImportance.Normal);


                    foreach (SPSolution solution in solutions)
                    {
                        if (solution.Name.Equals(checkName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            //solution found
                            if (solution.ContainsWebApplicationResource)
                            {

                                Log.LogMessageFromText("Solution '" + checkName + "' contains web application resource", MessageImportance.Normal);
                                webappSolutionArray.Add(ToTaskItem(checkName));
                            }
                            else
                            {
                                Log.LogMessageFromText("Solution '" + checkName + "' contains no web application resource", MessageImportance.Normal);
                                globalSolutionArray.Add(ToTaskItem(checkName));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }

            webapplicationSolutions = (ITaskItem[])webappSolutionArray.ToArray(typeof(ITaskItem));
            globallySolutions = (ITaskItem[])globalSolutionArray.ToArray(typeof(ITaskItem));

            return true;
        }

        private bool RunCheckIfSolutionExists()
        {
            if (Solutions == null)
            {
                return true;
            }

            bool throwException = false;
            string message = "";

            string[] solutionIds = Solutions.Split(new char[';']);

            Log.LogMessageFromText("Checking if solutions exists'" + Solutions + "'...", MessageImportance.Normal);
            try
            {
                SPSolutionCollection solutions = SPFarm.Local.Solutions;

                foreach (string solutionId in solutionIds)
                {
                    //is the parameter a solution id or a filename
                    Guid solutionGuid;
                    try
                    {
                        solutionGuid = new Guid(solutionId);

                        foreach (SPSolution solution in solutions)
                        {
                            if (solution.Id == solutionGuid)
                            {
                                //solution exists, failure
                                throwException = true;
                                message += solution.Name + ";";
                            }
                        }
                    }
                    catch (Exception)
                    {
                        string solutionName = "";

                        //ok, is not guid, try the filename
                        if (Path.IsPathRooted(solutionId))
                        {
                            if (File.Exists(solutionId))
                            {
                                solutionName = Path.GetFileName(solutionId);
                            }
                        }
                        else
                        {
                            solutionName = solutionId;
                        }

                        //check for the solution with the name
                        foreach (SPSolution solution in solutions)
                        {
                            if (solution.Name.Equals(solutionName, StringComparison.InvariantCultureIgnoreCase))
                            {
                                //solution exists, failure
                                throwException = true;
                                message += solutionName + ";";
                            }
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }

            if (throwException)
            {
                Log.LogErrorFromException(new Exception("Solutions already installed: " + message));
                return false;
            }
            else
            {
                Log.LogMessageFromText("Checking existing solutions sucessfully finished.", MessageImportance.Normal);
                return true;
            }
        }

        private bool RunCheckPrerequisiteSolutions()
        {
            if (Solutions == null)
            {
                return true;
            }

            bool throwException = false;
            string missingSolutions = "";

            string[] solutionIds = Solutions.Split(new char[';']);

            Log.LogMessageFromText("Checking prerequisite solutions '" + Solutions + "'...", MessageImportance.Normal);
            try
            {
                foreach (string solutionId in solutionIds)
                {
                    Log.LogMessageFromText("Checking solution '" + solutionId + "'.", MessageImportance.Normal);
                    bool solutionFound = false;
                    try
                    {
                        //try the check with the id
                        Guid solutionGuid = new Guid(solutionId);                    
                        SPSolutionCollection solutions = SPFarm.Local.Solutions;
                        foreach (SPSolution solution in solutions)
                        {
                            if (solution.Id == solutionGuid)
                            {
                                solutionFound = true;
                            }
                        }
                    }
                    catch { }

                    if (!solutionFound)
                    {
                        try
                        {
                            //try second check with name
                            SPSolutionCollection solutions = SPFarm.Local.Solutions;
                            foreach (SPSolution solution in solutions)
                            {
                                if (solution.Name.Equals(solutionId, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    solutionFound = true;
                                }
                            }
                        }
                        catch { }
                    }

                    if (!solutionFound)
                    {
                        throwException = true;
                        missingSolutions += solutionId + ";";
                    }
                }
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }

            if (throwException)
            {
                Log.LogErrorFromException(new Exception("Solutions not found: " + missingSolutions));
                return false;
            }
            else
            {
                Log.LogMessageFromText("Checking prerequisite solutions sucessfully finished.", MessageImportance.Normal);
                return true;
            }
        }

        private bool RunCheckWebExists()
        {
            Log.LogMessageFromText("Checking web '" + Url + "'...", MessageImportance.Normal);
            return true;
        }

        private bool RunCheckSiteExists()
        {
            Log.LogMessageFromText("Checking site collection '" + Url + "'...", MessageImportance.Normal);
            return true;
        }

        private bool RunCheckWebApplicationExists()
        {
            Log.LogMessageFromText("Checking web application '" + Url + "'...", MessageImportance.Normal);
            return true;
        }

        private bool RunCheckTimerServiceRunning()
        {
            Log.LogMessageFromText("Checking SharePoint timer service running (SPTimer) ...", MessageImportance.Normal);
            try
            {
                ServiceController sc = new ServiceController("SPTimerV3");
                if (sc.Status == ServiceControllerStatus.Running)
                {
                    return true;
                }
            }
            catch { }
            try
            {
                ServiceController scwss3 = new ServiceController("WSSTimerV3");
                if (scwss3.Status == ServiceControllerStatus.Running)
                {
                    return true;
                }
            }
            catch { }
            try
            {
                ServiceController sc4 = new ServiceController("SPTimerV4");
                if (sc4.Status == ServiceControllerStatus.Running)
                {
                    return true;
                }
            }
            catch { }
            try
            {
                ServiceController scwss4 = new ServiceController("WSSTimerV4");
                if (scwss4.Status == ServiceControllerStatus.Running)
                {
                    return true;
                }
            }
            catch { }

            Log.LogError("Service SPTimer not running.");
            return false;
        }

        private bool RunCheckAdminServiceRunning()
        {
            Log.LogMessageFromText("Checking admin service running (SPAdmin)...", MessageImportance.Normal);

            try
            {
                ServiceController sc = new ServiceController("SPAdmin");
                if (sc.Status == ServiceControllerStatus.Running)
                {
                    return true;
                }
            }
            catch { }

            try
            {
                ServiceController sc = new ServiceController("SPAdminV4");
                if (sc.Status == ServiceControllerStatus.Running)
                {
                    return true;
                }
            }
            catch { }

            Log.LogWarning("Service SPAdmin not running.");
            return true;
        }

        private bool RunCheckUserIsAdministrator()
        {
            Log.LogMessageFromText("Checking user is administrator...", MessageImportance.Normal);
            try
            {
                if (SPFarm.Local.CurrentUserIsAdministrator())
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
            }
            Log.LogError("User is not administrator.");
            return false;
        }

        private bool RunCheckMinimalVersionInstalled()
        {
            Log.LogMessageFromText("Checking minimal SharePoint version '" + MinimalVersion + "'...", MessageImportance.Normal);
            try
            {
                Version installedVersion = SPFarm.Local.BuildVersion;
                Version minimalVersion = new Version(MinimalVersion);
                if (installedVersion < minimalVersion)
                {
                    Log.LogErrorFromException(new Exception("Installed version " + installedVersion.ToString() + " is lower than necessary minimal version " + minimalVersion));
                    return false;
                }
            }
            catch (Exception ex)
            {
                Log.LogWarning("Could not check SharePoint version");
            }
            return true;
        }

        private bool RunCheckWSSInstalled()
        {
            Log.LogMessageFromText("Checking for WSS installation...", MessageImportance.Normal);

            string name = @"SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\12.0";
            string name14 = @"SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0";
            try
            {
                RegistryKey key = Registry.LocalMachine.OpenSubKey(name);
                if (key != null)
                {
                    object val = key.GetValue("SharePoint");
                    if (val != null && val.Equals("Installed"))
                    {
                        return true;
                    }
                }

            }
            catch (Exception ex)
            {

            }
            try
            {
                RegistryKey key = Registry.LocalMachine.OpenSubKey(name14);
                if (key != null)
                {
                    object val = key.GetValue("SharePoint");
                    if (val != null && val.Equals("Installed"))
                    {
                        return true;
                    }
                }

            }
            catch (Exception ex)
            {

            }
            Log.LogError("WSS not installed.");
            return false;
        }

        private bool RunCheckMOSSInstalled()
        {
            Log.LogMessageFromText("Checking for MOSS installation...", MessageImportance.Normal);

            string name = @"SOFTWARE\Microsoft\Office Server\12.0";
            string name14 = @"SOFTWARE\Microsoft\Office Server\14.0";
            try
            {
                RegistryKey key = Registry.LocalMachine.OpenSubKey(name);
                if (key != null)
                {
                    string versionStr = key.GetValue("BuildVersion") as string;
                    if (versionStr != null)
                    {
                        Version buildVersion = new Version(versionStr);
                        if (buildVersion.Major == 12)
                        {
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }

            try
            {
                RegistryKey key = Registry.LocalMachine.OpenSubKey(name14);
                if (key != null)
                {
                    string versionStr = key.GetValue("BuildVersion") as string;
                    if (versionStr != null)
                    {
                        Version buildVersion = new Version(versionStr);
                        if (buildVersion.Major == 14)
                        {
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }
            Log.LogError("MOSS not installed.");
            return false;
        }

        private void ExecAdmSvcJobs()
        {

            // First run the OOTB execadmsvcjobs on the local machine to make sure that any local jobs get executed

            foreach (SPServer server in SPFarm.Local.Servers)
            {
                // Only look at servers with a valid role.
                if (server.Role == SPServerRole.Invalid)
                    continue;

                // Don't need to check locally as we just ran the OOTB command locally so skip the local server.
                if (server.Id.Equals(SPServer.Local.Id))
                    continue;

                bool stillExecuting;
                //Log.LogMessageFromText("\rChecking jobs on {0}", server.Name);
                

                do
                {

                    stillExecuting = CheckApplicableRunningJobs(server, false);



                    // If jobs are still executing then sleep for 1 second.

                    if (stillExecuting)

                        System.Threading.Thread.Sleep(1000);

                }
                while (stillExecuting);

            }

        }


        /// <summary>

        /// Checks for applicable running jobs.

        /// </summary>

        /// <param name="server">The server.</param>

        /// <param name="quiet">if set to <c>true</c> [quiet].</param>

        /// <returns></returns>

        private bool CheckApplicableRunningJobs(SPServer server, bool quiet)
        {
            foreach (KeyValuePair<Guid, SPService> current in GetProvisionedServices(server))
            {

                SPService service = current.Value;

                SPAdministrationServiceJobDefinitionCollection definitions = new SPAdministrationServiceJobDefinitionCollection(service);

                if (CheckApplicableRunningJobs(server, definitions, quiet))

                    return true; // We've found running jobs so no point looking any further.  

                SPWebService service2 = service as SPWebService;
                if (service2 != null)
                {
                    foreach (SPWebApplication webApplication in service2.WebApplications)
                    {
                        definitions = new SPAdministrationServiceJobDefinitionCollection(webApplication);

                        if (CheckApplicableRunningJobs(server, definitions, quiet))
                            return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Checks for applicable running jobs.
        /// </summary>
        /// <param name="server">The server.</param>
        /// <param name="jds">The job definitions to consider.</param>
        /// <param name="quiet">if set to <c>true</c> [quiet].</param>
        /// <returns></returns>
        private bool CheckApplicableRunningJobs(SPServer server, SPAdministrationServiceJobDefinitionCollection jds, bool quiet)
        {
            bool stillExecuting = false;


            foreach (SPJobDefinition definition in jds)
            {
                if (string.IsNullOrEmpty(definition.Name))
                    continue;

                bool isApplicable = false;
                if (!definition.IsDisabled)
                    isApplicable = ((definition.Server == null) || definition.Server.Id.Equals(server.Id));

                if (!isApplicable)
                {
                    // If it's not applicable then we don't really care if it's running or not.
                    continue;
                }


                Log.LogMessageFromText("Waiting on " + definition.Name, MessageImportance.Normal);

                stillExecuting = true;
            }
            return stillExecuting;
        }

        /// <summary>
        /// Gets the provisioned services.
        /// </summary>
        /// <param name="server">The server.</param>
        /// <returns></returns>
        private Dictionary<Guid, SPService> GetProvisionedServices(SPServer server)
        {
            Dictionary<Guid, SPService> dictionary = new Dictionary<Guid, SPService>(8);

            foreach (SPServiceInstance serviceInstance in server.ServiceInstances)
            {
                SPService service = serviceInstance.Service;
                if (serviceInstance.Status == SPObjectStatus.Online)
                {
                    if (dictionary.ContainsKey(service.Id))
                        continue;
                    dictionary.Add(service.Id, service);
                }
            }
            return dictionary;

        }

        /// <summary>
        /// This class mimics the internal equivalent and is used because the base class is abstract.
        /// </summary>
        internal class SPAdministrationServiceJobDefinitionCollection : SPPersistedChildCollection<SPAdministrationServiceJobDefinition>
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="SPAdministrationServiceJobDefinitionCollection"/> class.
            /// </summary>
            /// <param name="service">The service.</param>
            internal SPAdministrationServiceJobDefinitionCollection(SPService service)
                : base(service)
            {
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="SPAdministrationServiceJobDefinitionCollection"/> class.
            /// </summary>
            /// <param name="webApplication">The web application.</param>

            internal SPAdministrationServiceJobDefinitionCollection(SPWebApplication webApplication)
                : base(webApplication)
            {
            }
        }

        internal bool EnsureRunning(string serviceName)
        {
          ServiceController sc = new ServiceController(serviceName);
          if (sc.Status == ServiceControllerStatus.Running)
          {
            return true;
          }
          else
          {
            Log.LogMessageFromText("Starting service...", MessageImportance.Normal);

            sc.Start();
            sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 0, 10));

            if (sc.Status == ServiceControllerStatus.Running)
            {
              return true;
            }
          }
          return false;
        }

    }
 }

